package com.truth.lock.executor.redistemplate;

import com.truth.lock.enumeration.TruthLockType;
import com.truth.lock.executor.TruthLockExecutor;
import com.truth.lock.factory.TruthExecutorBeanFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

public class RedisTemplateLockExecutor implements TruthLockExecutor<String> {

//    private static final RedisScript<String> SCRIPT_LOCK = new DefaultRedisScript<>(
//            "if redis.call('setNx',KEYS[1],ARGV[1]) then if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end end",
//            String.class);

    private static final RedisScript<String> SCRIPT_UNLOCK = new DefaultRedisScript<>("if redis.call('get',KEYS[1]) " +
            "== ARGV[1] then return tostring(redis.call('del', KEYS[1])==1) else return 'false' end", String.class);


    /**
     * StringRedisTemplate
     */
    private final StringRedisTemplate stringRedisTemplate;

    public RedisTemplateLockExecutor(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public String acquire(String lockKey, String lockValue, long expire, long acquireTimeout) {
        Boolean locked = stringRedisTemplate.opsForValue()
                .setIfAbsent(lockValue, lockValue, expire, TimeUnit.MILLISECONDS);
        return acquireLockInstance(Boolean.TRUE.equals(locked), String.valueOf(locked));
    }

    @Override
    public boolean releaseLock(String key, String value, String lockInstance) {
        String result = stringRedisTemplate.execute(
                SCRIPT_UNLOCK,
                stringRedisTemplate.getStringSerializer(),
                stringRedisTemplate.getStringSerializer(),
                Collections.singletonList(key), value);
        return Boolean.parseBoolean(result);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        TruthExecutorBeanFactory.register(TruthLockType.REST_TEMPLATE_LOCK, this);
    }
}
